package com.geezdata.cps.base.shiro;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.FilterChainManager;
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanInitializationException;

import com.google.common.base.Splitter;

public class MyShiroFilterFactoryBean extends ShiroFilterFactoryBean{
	private static final Logger logger = LoggerFactory.getLogger(MyShiroFilterFactoryBean.class);
	private List<String> noShiroIps = new ArrayList<String>();
	private List<String> noShiroUrls = new ArrayList<String>();
	
   public MyShiroFilterFactoryBean(String hosts) {
       super();
       if(StringUtils.isNotEmpty(hosts)) {
    	   noShiroIps = Splitter.on(",").splitToList(hosts);
       }
       noShiroUrls = NoShiroPostProcessor.getInstance();
   }

   @Override
   protected AbstractShiroFilter createInstance() throws Exception {
       SecurityManager securityManager = getSecurityManager();
       if (securityManager == null) {
           String msg = "SecurityManager property must be set.";
           throw new BeanInitializationException(msg);
       }

       if (!(securityManager instanceof WebSecurityManager)) {
           String msg = "The security manager does not implement the WebSecurityManager interface.";
           throw new BeanInitializationException(msg);
       }

       FilterChainManager manager = createFilterChainManager();

       PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
       chainResolver.setFilterChainManager(manager);

       return new MySpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
   }

   private final class MySpringShiroFilter extends AbstractShiroFilter {
       protected MySpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
           super();
           if (webSecurityManager == null) {
               throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
           }
           setSecurityManager(webSecurityManager);
           if (resolver != null) {
               setFilterChainResolver(resolver);
           }
       }

       @Override
       protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse,
               FilterChain chain) throws ServletException, IOException {
           HttpServletRequest request = (HttpServletRequest)servletRequest;
           String uri = request.getRequestURI().toLowerCase();
           boolean flag = true;
           if(noShiroIps.contains(getIpAddr(request)) && noShiroUrls.contains(uri)){
        	   flag = false;
           }
           if(flag){
        	   logger.info("shirouri=" + uri);
               super.doFilterInternal(servletRequest, servletResponse, chain);
           }else{
        	   logger.info("shironouri=" + uri);
               chain.doFilter(servletRequest, servletResponse);
           }
       }
       
       private String getIpAddr(HttpServletRequest request) {  
	   	    String ip = request.getHeader("x-forwarded-for");//先从nginx自定义配置获取  
	   	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
	   	        ip = request.getHeader("X-real-ip");  
	   	    }  
	   	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
	   	        ip = request.getHeader("Proxy-Client-IP");  
	   	    }  
	   	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
	   	        ip = request.getHeader("WL-Proxy-Client-IP");  
	   	    }  
	   	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
	   	        ip = request.getRemoteAddr();  
	   	    }  
	   	    return ip;  
	   	}

   }
}